package com.mall.search.server.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.mall.common.core.utils.StringUtils;
import com.mall.search.common.domain.SkuEsModel;
import com.mall.search.server.service.EsSearchService;
import com.mall.search.server.vo.SearchParam;
import com.mall.search.server.vo.SearchResult;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class EsSearchTwoServiceImpl implements EsSearchService{

    @Autowired
    private RestHighLevelClient client;


    @Override
    public SearchResult search(SearchParam searchParam) throws IOException {

        //创建查询对象
        SearchRequest searchRequest = BuidSearchRequest(searchParam);
        //执行查询操作
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        //解析查询返回结果
        SearchResult searchResult = analyzerResponse(searchResponse,searchParam);

        //返回结果集
        return searchResult;
    }

    private SearchResult analyzerResponse(SearchResponse searchResponse,SearchParam searchParam) {
        SearchResult searchResult = new SearchResult();
        //获取hits
        SearchHits hits = searchResponse.getHits();
        //创建返回商品对象
        ArrayList<SkuEsModel> skuEsModels = new ArrayList<>();
        //循环hits 获取每一个hit
        for (SearchHit hit : hits) {
            String skuModes = hit.getSourceAsString();
            SkuEsModel skuEsModel = JSONObject.parseObject(skuModes, SkuEsModel.class);
            skuEsModels.add(skuEsModel);

            //设置高亮
            if(StringUtils.isNotEmpty(searchParam.getKeyword())){
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                HighlightField skuTitleHighLight = highlightFields.get("skuTitle");
                skuEsModel.setSkuTitle(skuTitleHighLight.getFragments()[0].toString());
            }
        }
        //甚至聚合 品牌和分类列表，属性
        Aggregations aggregations = searchResponse.getAggregations();
        ParsedLongTerms brandIdAgg = aggregations.get("brandIdAgg");
        List<? extends Terms.Bucket> bucketsByBrandId = brandIdAgg.getBuckets();
        ArrayList<SearchResult.BrandVo> brandVos = new ArrayList<>();
        for (Terms.Bucket bucket : bucketsByBrandId) {
            SearchResult.BrandVo brandVo = new SearchResult.BrandVo();
            brandVo.setBrandId(Long.valueOf(bucket.getKeyAsString()));
            Terms brandNameAgg = bucket.getAggregations().get("brandNameAgg");
            String brandName = brandNameAgg.getBuckets().get(0).getKeyAsString();
            brandVo.setBrandName(brandName);
            Terms brandImgAgg = bucket.getAggregations().get(" brandImgAgg");
            if(brandImgAgg!=null){
                String brandImg = brandImgAgg.getBuckets().get(0).getKeyAsString();
                brandVo.setBrandImg(brandImg);
            }
            brandVos.add(brandVo);
        }

        ParsedLongTerms catalogIdAgg = aggregations.get("catalogIdAgg");
        ArrayList catalogVos = new ArrayList<SearchResult.CatalogVo>();
        for (Terms.Bucket bucket : catalogIdAgg.getBuckets()) {
            SearchResult.CatalogVo catalogVo = new SearchResult.CatalogVo();

            catalogVo.setCatalogId(Long.valueOf(bucket.getKeyAsString()));
            Terms catalogNameAgg = bucket.getAggregations().get("catalogNameAgg");
            String catalogName = catalogNameAgg.getBuckets().get(0).getKeyAsString();
            catalogVo.setCatalogName(catalogName);

            catalogVos.add(catalogVo);
        }
        ArrayList<SearchResult.AttrVo> attrVos = new ArrayList<>();

        ParsedNested attrAgg = aggregations.get("attrAgg");
        Aggregations attrAggAggregations = attrAgg.getAggregations();
        Terms attrIdAgg = attrAggAggregations.get("attrIdAgg");

        for (Terms.Bucket bucket : attrIdAgg.getBuckets()) {
            SearchResult.AttrVo attrVo = new SearchResult.AttrVo();

            attrVo.setAttrId(Long.valueOf(bucket.getKeyAsString()));

            Terms attrName = bucket.getAggregations().get("attrNameAgg");
            String attrVoName = attrName.getBuckets().get(0).getKeyAsString();
            attrVo.setAttrName(attrVoName);
            Terms attrValue = bucket.getAggregations().get("attrValueAgg");
            List<String> strings = new ArrayList<>();
            for (Terms.Bucket attrValueBucket : attrValue.getBuckets()) {
                String keyAsString = attrValueBucket.getKeyAsString();
                strings.add(keyAsString);
            }
            attrVo.setAttrValue(strings);

            attrVos.add(attrVo);
        }

        searchResult.setProducts(skuEsModels);
        searchResult.setBrands(brandVos);
        searchResult.setCatalogs(catalogVos);
        searchResult.setAttrs(attrVos);
        //分页参数
        /* 当前页码*/
       //private Integer pageNum;
        searchResult.setPageNum(searchParam.getPageNum());
        /* 总记录数*/
        //private Long total;
        searchResult.setTotal(hits.getTotalHits().value);
        /* 总页码*/
        //private Integer totalPages;
        searchResult.setTotalPages(
                Long.valueOf(searchResult.getTotal() % 20 == 0 ? searchResult.getTotal() / 20 : (searchResult.getTotal() / 20 + 1)).intValue()
        );


        return searchResult;
    }

    private SearchRequest BuidSearchRequest(SearchParam searchParam) {

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //关键词
        if(StringUtils.isNotEmpty(searchParam.getKeyword())){
            boolQueryBuilder.must(QueryBuilders.matchQuery("skuTitle",searchParam.getKeyword()));
        }

        //分类属性
        if(searchParam.getCatalog3Id()!=null){

            boolQueryBuilder.filter(QueryBuilders.termQuery("catalogId",searchParam.getCatalog3Id()));
        }

        //品牌id 225
        if(searchParam.getBrandId()!=null && searchParam.getBrandId().size()>0){

            boolQueryBuilder.filter(QueryBuilders.termsQuery("brandId",searchParam.getBrandId()));
        }


        //skuPrice价格 10_20000
        if(StringUtils.isNotBlank(searchParam.getSkuPrice())){
            RangeQueryBuilder skuPrice = QueryBuilders.rangeQuery("skuPrice");
            String[] price = searchParam.getSkuPrice().split("_");
            if(price.length==2){
                skuPrice.gte(price[0]);
                skuPrice.lte(price[1]);
            }else if(searchParam.getSkuPrice().startsWith("_")){
                skuPrice.lte(price[0]);
            }else if(searchParam.getSkuPrice().endsWith("_")){
                skuPrice.gte(price[0]);
            }

            // 添加到boolQueryBuilder
            boolQueryBuilder.filter(skuPrice);
        }

        //属性查询
        //attrs=1_3G:4G:5G,2_2020
        if(searchParam.getAttrs()!=null && searchParam.getAttrs().size()>0 ){
            for (String attr : searchParam.getAttrs()) {
                String[] str = attr.split("_");
                String attrId = str[0];
                String[] attrValue = str[1].split(":");

                BoolQueryBuilder nestBoolQueryBuilder = QueryBuilders.boolQuery();
                nestBoolQueryBuilder.must(QueryBuilders.termQuery("attrs.attrId",attrId));
                nestBoolQueryBuilder.must(QueryBuilders.termsQuery("attrs.attrValue",attrValue));
                NestedQueryBuilder attrs = QueryBuilders.nestedQuery("attrs", nestBoolQueryBuilder, ScoreMode.None);
                boolQueryBuilder.filter(attrs);
            }
        }


        searchSourceBuilder.query(boolQueryBuilder);


        //分页
        searchSourceBuilder.from(0);
        searchSourceBuilder.size(20);


        //高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("skuTitle");
        highlightBuilder.preTags("<span style='color:skyblue;font-size:18px'>");
        highlightBuilder.postTags("</span>");

        searchSourceBuilder.highlighter(highlightBuilder);


        //排序saleCount_asc/desc
        if(StringUtils.isNotEmpty(searchParam.getSort())){
            String sort = searchParam.getSort();
            String[] sorts = sort.split("/");
            searchSourceBuilder.sort(sorts[0],"asc".equalsIgnoreCase(sorts[1])?SortOrder.ASC:SortOrder.DESC);
        }



        //聚合
        TermsAggregationBuilder brandIdAgg = AggregationBuilders.terms("brandIdAgg").field("brandId");
        TermsAggregationBuilder brandNameAgg = AggregationBuilders.terms("brandNameAgg").field("brandName");
        TermsAggregationBuilder brandImgAgg = AggregationBuilders.terms("brandImgAgg").field("brandImg");
        brandIdAgg.subAggregation(brandNameAgg);
        brandIdAgg.subAggregation(brandImgAgg);


        TermsAggregationBuilder catalogIdAgg = AggregationBuilders.terms("catalogIdAgg").field("catalogId");
        TermsAggregationBuilder catalogNameAgg = AggregationBuilders.terms("catalogNameAgg").field("catalogName");

        catalogIdAgg.subAggregation(catalogNameAgg);
        brandIdAgg.subAggregation(catalogIdAgg);

        NestedAggregationBuilder nested = AggregationBuilders.nested("attrAgg", "attrs");
        TermsAggregationBuilder attrIdAgg = AggregationBuilders.terms("attrIdAgg").field("attr.attrId");
        TermsAggregationBuilder attrNameAgg = AggregationBuilders.terms("attrNameAgg").field("attr.attrName");
        TermsAggregationBuilder attrValueAgg = AggregationBuilders.terms("attrValueAgg").field("attr.attrValue");

        nested.subAggregation(attrIdAgg);
        attrIdAgg.subAggregation(attrNameAgg);
        attrIdAgg.subAggregation(attrValueAgg);



        searchSourceBuilder.aggregation(nested);
        searchSourceBuilder.aggregation(catalogIdAgg);
        searchSourceBuilder.aggregation(brandIdAgg);

        //searchSourceBuilder.query(boolQueryBuilder);

        SearchRequest searchRequest = new SearchRequest();
        searchRequest.source(searchSourceBuilder);
        searchRequest.indices("product");

        return searchRequest;
    }
}
